package org.kanstantin.nwscan.crawler.network;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.logging.Logger;

/**
 * @author kanstantin
 */
public class IPBasedHostFinder implements HostFinder {
    private AddressRange addressRange = null;
    private int timeout = 300;
    private int syncDelay = 500;

    private static int threads = 0;

    public IPBasedHostFinder(AddressRange ar) {
        this.addressRange = ar;
    }

    private List<String> HostList = Collections.synchronizedList(new ArrayList<String>());

    private Logger Log = Logger.getLogger(IPBasedHostFinder.class.getName());

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public void setSyncDelay(int syncDelay) {
        this.syncDelay = syncDelay;
    }

    @Override
    public void scan() {

        Log.info("start from ip: " + addressRange.getFirstAddrAsString());
        Log.info(" stop scan at: " + addressRange.getLastAddrAsString());

        for (long i = addressRange.getFirstAddrAsInteger(); i <= addressRange.getLastAddrAsInteger(); i++) {
            new IpHostFinder(AddressRange.convertToString(i)).start();
        }

        do {
            delay(syncDelay);
        } while (threads > 0);

        Log.info("Scanning done, found " + HostList.size() + " hosts");
    }

    private void delay(int millis) {
        try {
            Thread.currentThread().sleep(millis);
        } catch (InterruptedException ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public List<String> getHostList() {
        return this.HostList;
    }

    private synchronized void incThreads() {

        threads++;
    }

    private synchronized void decThreads() {

        threads--;
    }


    class IpHostFinder extends Thread {
        private InetAddress host;

        IpHostFinder(String ipaddress) {
            this.host = getInetAddress(ipaddress);
        }

        public void run() {
            incThreads();

            if (host != null && isAlive(host)) {
                HostList.add(host.getHostName());
            }

            decThreads();
        }

        private InetAddress getInetAddress(String ipaddress) {

            InetAddress host = null;
            try {
                host = InetAddress.getByName(ipaddress);
            } catch (UnknownHostException ex) {
                // just do nothing
            }

            return host;
        }


        private boolean isAlive(InetAddress host) {
            boolean res = false;
            try {
                res = host.isReachable(timeout);
            } catch (IOException ioe) {
                // just do nothing
            }
            return res;
        }

        public boolean pseudoPing(InetAddress host) {
            boolean res = false;
            try {
                Socket t = new Socket(host, 7);
                DataInputStream dis = new DataInputStream(t.getInputStream());
                PrintStream ps = new PrintStream(t.getOutputStream());
                ps.println("Hello");
                String str = dis.readLine();
                if (str.equals("Hello"))
                    res = true;
                t.close();
            } catch (IOException e) {
                // do nothing
            }
            return res;
        }
    }
}
